#ifndef FILE_INCLUDED
#define FILE_INCLUDED

#include <string.h>
#include <stdlib.h>
#include "fileblock.h"
#include "directory.h"

#define EMPTY_FILE_NAME ""
#define MAX_FILENAME_LENGTH 16

typedef struct {
	char fileName[MAX_FILENAME_LENGTH + 1];
	uint32_t size;
	directory_index_t parentDirectory;
	sector_t firstBlock;
} File;

void file_initEmpty( File * file )
{
	strcpy( file->fileName, EMPTY_FILE_NAME );
}

int file_init( File * file, const char * name, directory_index_t parent )
{
	if ( strlen( name ) > MAX_FILENAME_LENGTH || strcmp( name, EMPTY_FILE_NAME ) == 0 )
		return -1;

	memcpy( file->fileName, name, MAX_FILENAME_LENGTH + 1 );
	file->parentDirectory = parent;
	file->size = 0;
	file->firstBlock.in_use = 0;

	return 0;
}

int file_loadFromDisk( const File * file, char ** out )
{
    if ( file->size == 0 )
        return 0;

    char * ret = malloc( file->size );

    size_t remainingTransfer = file->size;
    size_t i = 0;
    sector_t temp = file->firstBlock;
    while ( temp.in_use ) {
        FileBlock fb;
        while ( SD_read( temp.sector, &fb ) != 0 );

        size_t toTransfer = ( remainingTransfer > FILEBLOCK_DATA_LENGTH ) ? FILEBLOCK_DATA_LENGTH : remainingTransfer;

        memcpy( ret + FILEBLOCK_DATA_LENGTH * i++, fb.data, toTransfer );
        remainingTransfer -= toTransfer;
        temp = fb.next;
    }

    if ( remainingTransfer != 0 ) {
        free( ret );
        return -1;
    }

    *out = ret;
    return 0;
}

int file_writeToDisk( const File * file, char * data )
{
    if ( file->size == 0 )
        return 0;

    size_t i = 0;
    size_t remainingTransfer = file->size;
    sector_t temp = file->firstBlock;

    while ( temp.in_use )
    {
        FileBlock block;
        while ( SD_read( temp.sector, &block ) != 0 );

        size_t toTransfer = ( remainingTransfer > FILEBLOCK_DATA_LENGTH ) ? FILEBLOCK_DATA_LENGTH : remainingTransfer;
        memcpy( block.data, data + FILEBLOCK_DATA_LENGTH * i++, toTransfer );
        remainingTransfer -= toTransfer;

        while ( SD_write( temp.sector, &block ) != 0 );

        temp = block.next;
    }

    if ( remainingTransfer != 0 )
        return -1;

    free( data );
    return 0;
}

void file_addFileBlock( File * file, sector_t sector )
{
    //Initialize node on disk
    FileBlock node;
    node.next.in_use = false;
    while ( SD_write( sector.sector, &node ) != 0 );

    //If head node is not in use
    if ( !file->firstBlock.in_use ) {
        file->firstBlock = sector;
        return;
    }

    //Read blocks until one is not in use;
    sector_t node_sector = file->firstBlock;

    while( SD_read( node_sector.sector, &node ) != 0 );

    while ( node.next.in_use )
    {
        node_sector = node.next;
        while( SD_read( node_sector.sector, &node ) != 0 );
    }

    //Set next node to sector and write back to disk
    node.next = sector;
    while ( SD_write( node_sector.sector, &node )  != 0 );
}

bool file_isEmpty( const File * file )
{
	return ( strcmp( file->fileName, EMPTY_FILE_NAME ) == 0 );
}

#endif
